package com.dd.cloud.user.service.patient.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.config.sms.SmsComponent;
import com.dd.cloud.common.constants.UserConstants;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.common.utils.DateUtils;
import com.dd.cloud.common.utils.PinYinUtils;
import com.dd.cloud.common.utils.SerialNumberUtils;
import com.dd.cloud.common.utils.ValidatorUtils;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.user.entity.doctor.PatientDeliveryAddr;
import com.dd.cloud.user.entity.doctor.PatientMedCard;
import com.dd.cloud.user.entity.patient.PatientAddressLink;
import com.dd.cloud.user.entity.patient.PatientMedRank;
import com.dd.cloud.user.entity.patient.PatientUserAddress;
import com.dd.cloud.user.mapper.patient.PatientMedRankMapper;
import com.dd.cloud.user.req.patient.PatientMedCardAddReq;
import com.dd.cloud.user.req.patient.PatientMedCardUpdateReq;
import com.dd.cloud.user.res.patient.PatientMedCardBindRes;
import com.dd.cloud.user.service.doctor.IPatientDeliveryAddrService;
import com.dd.cloud.user.service.doctor.IPatientMedCardService;
import com.dd.cloud.user.service.patient.IPatientAddressLinkService;
import com.dd.cloud.user.service.patient.IPatientMedRankService;
import com.dd.cloud.user.service.patient.IPatientUserAddressService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author czg
 * @since 2023-07-12
 */
@Service
public class PatientMedRankServiceImpl extends ServiceImpl<PatientMedRankMapper, PatientMedRank> implements IPatientMedRankService {
    @Autowired
    private SmsComponent smsComponent;
    @Autowired
    private IPatientMedCardService patientMedCardService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private IPatientUserAddressService patientUserAddressService;

    @Autowired
    private IPatientDeliveryAddrService patientDeliveryAddrService;

    @Autowired
    private IPatientAddressLinkService patientAddressLinkService;

    @Autowired
    private IPatientMedRankService patientMedRankService;


    /**
     * @param :
     * @return Map<Integer, List < PatientMedCardBindRes>> 按照患者关系分组
     * @description 查询患者绑定的就诊卡列表
     * @author czg
     * @date 2023/7/12 10:42
     */
    @Override
    public Map<Integer, List<PatientMedCardBindRes>> bindMedList() {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get();

        List<PatientMedCardBindRes> list = getBaseMapper().bindMedList(loginInfo.getId());
        Map<Integer, List<PatientMedCardBindRes>> map = new HashMap<>();
        list.stream().forEach(item -> {
            if (map.containsKey(item.getNexus())) {
                List<PatientMedCardBindRes> patientMedCardBindRes = map.get(item.getNexus());
                patientMedCardBindRes.add(item);
                map.put(item.getNexus(), patientMedCardBindRes);
            } else {
                List<PatientMedCardBindRes> itList = new ArrayList<>();
                itList.add(item);
                map.put(item.getNexus(), itList);
            }
        });
        return map;
    }

    /**
     * @param :
     * @return PatientMedCardBindRes
     * @description 查询患者最后一次使用的就诊卡
     * @author czg
     * @date 2023/7/12 11:06
     */
    @Override
    public PatientMedCardBindRes lastUseMed() {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get();
        PatientMedCardBindRes res = getBaseMapper().lastUseMed(loginInfo.getId());
        return res;
    }

    /**
     * @param :
     * @return void
     * @description 患者添加就诊卡 和验证同步信息统一接口,
     * @author czg
     * @date 2023/7/12 14:31
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void medAdd(PatientMedCardAddReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get();
        QueryWrapper<PatientMedCard> qu = new QueryWrapper<>();
        qu.lambda().eq(PatientMedCard::getCardType, req.getCardType()).eq(PatientMedCard::getIdCard, req.getIdCard()).eq(PatientMedCard::getStatus, UserConstants.MedCardStatus.NORMAL).last("limit 1");
        PatientMedCard cardOne = patientMedCardService.getOne(qu);
        if (req.getCardCheck() == 0 && cardOne != null) {
            //未确认是否同步, 弹出异常并返回同步信息
            throw new ZekeException("该身份证已存在，是否同步就诊人信息？", cardOne);
        }
        QueryWrapper<PatientMedCard> qw = new QueryWrapper<>();
        qw.lambda().eq(PatientMedCard::getMobileNumber, req.getMobileNumber()).eq(PatientMedCard::getStatus, UserConstants.MedCardStatus.NORMAL).last("limit 1");
        PatientMedCard mobOne = patientMedCardService.getOne(qw);
        if (req.getPhoneCheck() == 0 && mobOne != null) {
            //未确认是否同步, 弹出异常并返回同步信息
            throw new ZekeException("该手机号已存在，是否同步就诊人信息？", mobOne);
        }
        smsComponent.verifyPhoneCode(req.getMobileNumber(), req.getCode());
        if (req.getBirthDate() == null) {
            if (req.getAge() == null && req.getAgeType() == null) {
                throw new ZekeException(400, "出生日期或年龄数必须选择一个");
            }
            req.setBirthDate(DateUtils.byAgeNumAndAgeTypeToDate(req.getAge(), req.getAgeType()));
        }
        //手动验证参数
        ValidatorUtils.verify(req, PatientMedCardAddReq.class);
        PatientMedCard card = new PatientMedCard();

        if (req.getId() != null) {
            card = patientMedCardService.getById(req.getId());
            BeanUtils.copyProperties(req, card);
            String img = getPhotoImg(req.getSex());
            card.setAvatar(img);
            boolean update = patientMedCardService.updateById(card);
            if (!update) {
                throw new ZekeException("同步修改就诊卡失败");
            }
        } else {
            BeanUtils.copyProperties(req, card);
            String medNo = SerialNumberUtils.getInstance().medSerialNumber(redisTemplate);
            while (true) {
                QueryWrapper<PatientMedCard> qws = new QueryWrapper<>();
                qws.lambda().eq(PatientMedCard::getMedId, medNo);
                List<PatientMedCard> exist = patientMedCardService.list(qws);
                if (exist == null || exist.isEmpty()) {
                    break;
                }
                medNo = SerialNumberUtils.getInstance().medSerialNumber(redisTemplate);
            }
            String img = getPhotoImg(req.getSex());
            card.setAvatar(img);
            card.setMedId(medNo);
            card.setStatus(UserConstants.MedCardStatus.NORMAL);
            card.setCreateDate(LocalDateTime.now());
            card.setNamePinyin(PinYinUtils.chineseToPinyinSell(card.getName()));
            card.setCreateId(loginInfo.getId());
            boolean save = patientMedCardService.save(card);
            if (!save) {
                throw new ZekeException("添加就诊卡失败");
            }
        }

        /**
         * 绑定患者和就诊卡, 有可能当前卡已存在并绑定, 先删除患者和就诊卡直接的绑定
         */
        UpdateWrapper<PatientMedRank> uw = new UpdateWrapper<>();
        uw.lambda().eq(PatientMedRank::getPatientId, loginInfo.getId()).eq(PatientMedRank::getMedId, card.getMedId()).eq(PatientMedRank::getStatus, UserConstants.MedCardStatus.NORMAL).set(PatientMedRank::getStatus, UserConstants.MedCardStatus.DEL);
        update(uw);
        uw.clear();
        //删除最后一次使用的卡
        uw.lambda().eq(PatientMedRank::getPatientId, loginInfo.getId()).eq(PatientMedRank::getStatus, UserConstants.MedCardStatus.NORMAL).set(PatientMedRank::getLastUse, UserConstants.MedCardPatientLastUse.NO);
        update(uw);
        PatientMedRank patientMedRank = new PatientMedRank();
        patientMedRank.setPatientId(loginInfo.getId());
        patientMedRank.setMedId(card.getMedId());
        patientMedRank.setCreateDate(LocalDateTime.now());
        patientMedRank.setNexus(req.getNexus());
        patientMedRank.setStatus(UserConstants.MedCardStatus.NORMAL);
        patientMedRank.setLastUse(UserConstants.MedCardPatientLastUse.YES);
        boolean save = save(patientMedRank);
        if (!save) {
            throw new ZekeException("绑定就诊卡失败");
        }
        //给就诊人绑定地址
        bindAddress(card.getMedId(), loginInfo.getId());
    }

    public String getPhotoImg(String sex) {
        if ("女".equals(sex)) {
            return "https://zk-ak.obs.cn-south-1.myhuaweicloud.com/dadao/img_woman.png";
        } else if ("男".equals(sex)) {
            return "https://zk-ak.obs.cn-south-1.myhuaweicloud.com/dadao/img_man.png";
        }
        return "https://zk-ak.obs.cn-south-1.myhuaweicloud.com/dadao/img_man.png";
    }

    private void bindAddress(String medId, Integer userId) {
        //查询用户添加的地址
        LambdaQueryWrapper<PatientUserAddress> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatientUserAddress::getUserId, userId).eq(PatientUserAddress::getStatus, 1);
        List<PatientUserAddress> patientUserAddresses = patientUserAddressService.list(wrapper);
        if (CollectionUtil.isNotEmpty(patientUserAddresses)) {
            List<PatientAddressLink> patientAddressLinkList = new ArrayList<>();
            for (PatientUserAddress patientUserAddress : patientUserAddresses) {
                PatientDeliveryAddr patientDeliveryAddr = new PatientDeliveryAddr();
                patientDeliveryAddr.setDistrict(patientUserAddress.getDistrict()).setCity(patientUserAddress.getCity()).setProvince(patientUserAddress.getProvince()).setAddr(patientUserAddress.getAddr()).setReceiver(patientUserAddress.getReceiver()).setMedId(medId).setMobileNumber(patientUserAddress.getMobileNumber()).setCreateDate(patientUserAddress.getCreateDate()).setType(0).setStatus(1);
                patientDeliveryAddrService.save(patientDeliveryAddr);
                PatientAddressLink patientAddressLink = new PatientAddressLink();
                patientAddressLink.setMedAddressId(patientDeliveryAddr.getId()).setUserAddressId(patientUserAddress.getId()).setStatus(1);
                patientAddressLinkList.add(patientAddressLink);
            }
            if (CollectionUtil.isNotEmpty(patientAddressLinkList)) {
                patientAddressLinkService.saveBatch(patientAddressLinkList);
            }
        }
    }

    /**
     * @param id: 就诊人的id
     * @return void
     * @description 患者选择就诊人
     * @author czg
     * @date 2023/7/12 15:05
     */
    @Override
    public void setUseMed(String medId) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get();
        UpdateWrapper<PatientMedRank> uw = new UpdateWrapper<>();
        uw.lambda().eq(PatientMedRank::getPatientId, loginInfo.getId()).eq(PatientMedRank::getStatus, UserConstants.MedCardStatus.NORMAL).set(PatientMedRank::getLastUse, UserConstants.MedCardPatientLastUse.NO);
        update(uw);
        uw.clear();
        uw.lambda().eq(PatientMedRank::getMedId, medId).eq(PatientMedRank::getPatientId, loginInfo.getId()).set(PatientMedRank::getLastUse, UserConstants.MedCardPatientLastUse.YES);
        //辅助功能, 修改失败先不抛异常
        update(uw);
    }

    /**
     * @param id:
     * @return PatientMedCard
     * @description 就诊卡id查询就诊人
     * @author czg
     * @date 2023/7/14 14:39
     */
    @Override
    public PatientMedCard medById(Integer id) {
        PatientMedCard patientMedCard = patientMedCardService.getById(id);
        if (patientMedCard == null) {
            return new PatientMedCard();
        }
        LambdaQueryWrapper<PatientMedRank> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatientMedRank::getMedId, patientMedCard.getMedId()).eq(PatientMedRank::getStatus, UserConstants.MedCardStatus.NORMAL).last("limit 1");
        PatientMedRank patientMedRank = patientMedRankService.getOne(wrapper);
        if (patientMedCard != null && patientMedRank != null) {
            patientMedCard.setNexus(patientMedRank.getNexus());
        }
        return patientMedCard;
    }

    /**
     * @param req:
     * @return void
     * @description 患者修改就诊卡
     * @author czg
     * @date 2023/7/14 14:44
     */
    @Override
    public void medUpdate(PatientMedCardUpdateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get();
        PatientMedCard medCard = patientMedCardService.getById(req.getId());
        if (medCard == null) {
            throw new ZekeException("就诊卡id不存在");
        }
        if (!medCard.getCardType().equals(req.getCardType()) && !Objects.equals(medCard.getIdCard(), req.getIdCard())) {
            //修改了证件信息
            QueryWrapper<PatientMedCard> qw = new QueryWrapper<>();
            qw.lambda().eq(PatientMedCard::getCardType, req.getCardType()).eq(PatientMedCard::getIdCard, req.getIdCard()).eq(PatientMedCard::getStatus, UserConstants.MedCardStatus.NORMAL);
            PatientMedCard one = patientMedCardService.getOne(qw);
            if (one != null) {
                throw new ZekeException("证件类型与证件号码已存在,请更换");
            }
        }

        if (!medCard.getMobileNumber().equals(req.getMobileNumber())) {
            //修改了手机号
            QueryWrapper<PatientMedCard> qw = new QueryWrapper<>();
            qw.lambda().eq(PatientMedCard::getMobileNumber, req.getMobileNumber()).eq(PatientMedCard::getStatus, UserConstants.MedCardStatus.NORMAL);
            PatientMedCard one = patientMedCardService.getOne(qw);
            if (one != null) {
                throw new ZekeException("手机号码已存在,请更换");
            }
        }

        BeanUtils.copyProperties(req, medCard);
        if (!medCard.getName().equals(req.getName())) {
            medCard.setNamePinyin(PinYinUtils.chineseToPinyinSell(req.getName()));
        }
        String img = getPhotoImg(req.getSex());
        medCard.setAvatar(img);
        boolean byId = patientMedCardService.updateById(medCard);
        if (!byId) {
            throw new ZekeException("修改就诊卡失败");
        }

        QueryWrapper<PatientMedRank> qs = new QueryWrapper<>();
        qs.lambda().eq(PatientMedRank::getPatientId, loginInfo.getId()).eq(PatientMedRank::getMedId, medCard.getMedId()).eq(PatientMedRank::getStatus, UserConstants.MedCardStatus.NORMAL);
        PatientMedRank one = getOne(qs);
        if (one != null) {
            if (!req.getNexus().equals(one.getNexus())) {
                //修改了关系
                one.setNexus(req.getNexus());
                boolean b = updateById(one);
                if (!b) {
                    throw new ZekeException("修改就诊卡失败");
                }
            }
        }
    }

    /**
     * @param id: 就诊卡id
     * @return void
     * @description 患者解绑就诊卡
     * @author czg
     * @date 2023/7/14 14:44
     */
    @Override
    public void medBindRelieve(Integer id) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get();
        PatientMedCard medCard = patientMedCardService.getById(id);
        if (medCard == null) {
            throw new ZekeException("就诊卡id不存在");
        }
        QueryWrapper<PatientMedRank> qs = new QueryWrapper<>();
        qs.lambda().eq(PatientMedRank::getPatientId, loginInfo.getId()).eq(PatientMedRank::getMedId, medCard.getMedId()).eq(PatientMedRank::getStatus, UserConstants.MedCardStatus.NORMAL);
        PatientMedRank one = getOne(qs);
        if (one != null) {
            one.setStatus(UserConstants.MedCardStatus.DEL);
            boolean b = updateById(one);
            if (!b) {
                throw new ZekeException("解绑就诊卡失败");
            }
        }
        //删除就诊人所属用户地址
        relieveAddress(medCard.getMedId(), loginInfo.getId());
    }


    @Override
    public void relieveAddress(String medId, Integer userId) {
        LambdaQueryWrapper<PatientUserAddress> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatientUserAddress::getUserId, userId).eq(PatientUserAddress::getStatus, 1);
        List<PatientUserAddress> patientUserAddressList = patientUserAddressService.list(wrapper);
        if (CollectionUtil.isNotEmpty(patientUserAddressList)) {
            List<Integer> addressLinkIds = patientUserAddressList.stream().map(PatientUserAddress::getId).collect(Collectors.toList());
            List<PatientAddressLink> patientAddressLinks = this.getBaseMapper().queryRelieveAddress(medId, addressLinkIds);
            if (CollectionUtil.isNotEmpty(patientAddressLinks)) {
                List<Integer> linkIds = patientAddressLinks.stream().map(PatientAddressLink::getId).collect(Collectors.toList());
                List<Integer> medAddressIds = patientAddressLinks.stream().map(PatientAddressLink::getMedAddressId).collect(Collectors.toList());
                //删除该就诊人的地址关联
                LambdaUpdateWrapper<PatientAddressLink> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.in(PatientAddressLink::getId, linkIds).set(PatientAddressLink::getStatus, -1);
                patientAddressLinkService.update(updateWrapper);
                //删除就诊人地址
                LambdaUpdateWrapper<PatientDeliveryAddr> addrLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                addrLambdaUpdateWrapper.in(PatientDeliveryAddr::getId, medAddressIds).set(PatientDeliveryAddr::getStatus, -1);
                patientDeliveryAddrService.update(addrLambdaUpdateWrapper);
            }
        }
    }

    @Override
    public PatientMedCard queryPatientInfo() {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.PATIENT).get();
        Integer userId = loginInfo.getId();
        LambdaQueryWrapper<PatientMedRank> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PatientMedRank::getStatus, 1).eq(PatientMedRank::getPatientId, userId).eq(PatientMedRank::getNexus, 1).orderByDesc(PatientMedRank::getCreateDate).last("limit 1");
        PatientMedRank patientMedRank = this.getOne(queryWrapper);
        if (patientMedRank != null) {
            String medId = patientMedRank.getMedId();
            LambdaQueryWrapper<PatientMedCard> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(PatientMedCard::getMedId, medId).eq(PatientMedCard::getStatus, 1);
            PatientMedCard patientMedCard = patientMedCardService.getOne(wrapper);
            if (patientMedCard != null) {
                patientMedCard.setNexus(patientMedRank.getNexus());
            }
            return patientMedCard;
        }
        return new PatientMedCard();
    }

    /**
     * 查询患者id列表 通过就诊卡
     *
     * @param medId
     * @return
     */
    @Override
    public List<Integer> queryPatientIdListByMedId(String medId) {
        QueryWrapper<PatientMedRank> qw = new QueryWrapper<>();
        qw.lambda().eq(PatientMedRank::getMedId, medId);
        qw.lambda().eq(PatientMedRank::getStatus, 1);
        qw.lambda().eq(PatientMedRank::getNexus, 1);
        qw.lambda().select(PatientMedRank::getPatientId);
        List<PatientMedRank> list = list(qw);
        if (list == null) {
            list = new ArrayList<>();
        }
        return list.stream().map(PatientMedRank::getPatientId).distinct().collect(Collectors.toList());
    }
}
